// JavaScript 并发处理详解

console.log('=== 🚀 JavaScript 并发处理教程 ===')

// ============== 1. 什么是并发？ ==============
console.log('\n--- 📝 1. 什么是并发？ ---')
console.log('并发 = 同时处理多个任务，提高程序效率')
console.log('前端常见场景：')
console.log('- 同时发送多个API请求')
console.log('- 批量处理文件上传')
console.log('- 并行数据获取和处理')
console.log('- 防止请求阻塞用户界面')

// ============== 2. Promise.all - 全部成功才成功 ==============
console.log('\n--- ⚡ 2. Promise.all - 并发执行，全部成功 ---')

// 模拟API请求
function mockAPI(name, delay, shouldFail = false) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (shouldFail) {
        reject(new Error(`${name} 请求失败`))
      } else {
        resolve(`${name} 数据`)
      }
    }, delay)
  })
}

// Promise.all 示例
async function demonstratePromiseAll() {
  console.log('🚀 开始并发请求...')
  const startTime = Date.now()
  
  try {
    // 同时发起3个请求
    const results = await Promise.all([
      mockAPI('用户信息', 1000),
      mockAPI('订单列表', 1500),
      mockAPI('商品数据', 800)
    ])
    
    const endTime = Date.now()
    console.log('✅ Promise.all 成功:')
    console.log('结果:', results)
    console.log(`⏱️ 总耗时: ${endTime - startTime}ms (并发执行)`)
    
  } catch (error) {
    console.log('❌ Promise.all 失败:', error.message)
  }
}

// 对比：串行执行 vs 并行执行
async function compareSerialVsParallel() {
  console.log('\n📊 对比：串行 vs 并行')
  
  // 串行执行
  console.log('1. 串行执行:')
  const serialStart = Date.now()
  
  const result1 = await mockAPI('请求1', 500)
  const result2 = await mockAPI('请求2', 500)
  const result3 = await mockAPI('请求3', 500)
  
  const serialEnd = Date.now()
  console.log(`串行结果: [${result1}, ${result2}, ${result3}]`)
  console.log(`串行耗时: ${serialEnd - serialStart}ms`)
  
  // 并行执行
  console.log('\n2. 并行执行:')
  const parallelStart = Date.now()
  
  const parallelResults = await Promise.all([
    mockAPI('请求1', 500),
    mockAPI('请求2', 500),
    mockAPI('请求3', 500)
  ])
  
  const parallelEnd = Date.now()
  console.log(`并行结果: [${parallelResults.join(', ')}]`)
  console.log(`并行耗时: ${parallelEnd - parallelStart}ms`)
  console.log(`⚡ 提速: ${Math.round((serialEnd - serialStart) / (parallelEnd - parallelStart))}倍`)
}

// ============== 3. Promise.allSettled - 等待全部完成 ==============
console.log('\n--- 🛡️ 3. Promise.allSettled - 容错处理 ---')

async function demonstratePromiseAllSettled() {
  console.log('🚀 Promise.allSettled 示例（包含失败请求）:')
  
  const results = await Promise.allSettled([
    mockAPI('成功请求1', 500),
    mockAPI('失败请求', 600, true),  // 故意失败
    mockAPI('成功请求2', 700)
  ])
  
  console.log('📋 所有请求完成:')
  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`  ✅ 请求${index + 1}: ${result.value}`)
    } else {
      console.log(`  ❌ 请求${index + 1}: ${result.reason.message}`)
    }
  })
}

// ============== 4. Promise.race - 竞速执行 ==============
console.log('\n--- 🏁 4. Promise.race - 竞速执行 ---')

async function demonstratePromiseRace() {
  console.log('🚀 Promise.race 示例（取最快的）:')
  
  try {
    const fastest = await Promise.race([
      mockAPI('慢速服务器', 2000),
      mockAPI('中速服务器', 1000),
      mockAPI('快速服务器', 500)
    ])
    
    console.log('🏆 最快响应:', fastest)
  } catch (error) {
    console.log('❌ Race 失败:', error.message)
  }
}

// 超时控制示例
function createTimeout(ms) {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error('请求超时')), ms)
  })
}

async function requestWithTimeout(api, timeout = 3000) {
  try {
    const result = await Promise.race([
      api,
      createTimeout(timeout)
    ])
    return result
  } catch (error) {
    throw error
  }
}

// ============== 5. 并发控制 - 限制同时执行数量 ==============
console.log('\n--- 🎛️ 5. 并发控制 - 限制同时执行数量 ---')

class ConcurrencyController {
  constructor(limit = 3) {
    this.limit = limit      // 最大并发数
    this.running = 0        // 当前运行数
    this.queue = []         // 等待队列
  }
  
  async run(task) {
    return new Promise((resolve, reject) => {
      this.queue.push({
        task,
        resolve,
        reject
      })
      this.process()
    })
  }
  
  async process() {
    if (this.running >= this.limit || this.queue.length === 0) {
      return
    }
    
    this.running++
    const { task, resolve, reject } = this.queue.shift()
    
    try {
      const result = await task()
      resolve(result)
    } catch (error) {
      reject(error)
    } finally {
      this.running--
      this.process() // 处理下一个任务
    }
  }
}

// 测试并发控制
async function testConcurrencyControl() {
  console.log('🎛️ 并发控制测试（最多3个同时执行）:')
  
  const controller = new ConcurrencyController(3)
  const tasks = []
  
  // 创建10个任务
  for (let i = 1; i <= 10; i++) {
    tasks.push(
      controller.run(() => {
        console.log(`  🚀 任务${i} 开始执行`)
        return mockAPI(`任务${i}`, Math.random() * 1000 + 500)
      })
    )
  }
  
  console.log('📋 等待所有任务完成...')
  const results = await Promise.all(tasks)
  console.log('✅ 所有任务完成:', results.length, '个')
}

// ============== 6. 请求去重 - 防止重复请求 ==============
console.log('\n--- 🔄 6. 请求去重 - 防止重复请求 ---')

class RequestDeduplicator {
  constructor() {
    this.cache = new Map()
  }
  
  async request(key, requestFn) {
    // 如果正在请求中，返回相同的Promise
    if (this.cache.has(key)) {
      console.log(`🔄 复用请求: ${key}`)
      return this.cache.get(key)
    }
    
    // 创建新请求
    console.log(`🚀 新请求: ${key}`)
    const promise = requestFn().finally(() => {
      // 请求完成后清除缓存
      this.cache.delete(key)
    })
    
    this.cache.set(key, promise)
    return promise
  }
}

// 测试请求去重
async function testRequestDeduplication() {
  console.log('🔄 请求去重测试:')
  
  const deduplicator = new RequestDeduplicator()
  
  // 同时发起多个相同请求
  const requests = [
    deduplicator.request('userInfo', () => mockAPI('用户信息', 1000)),
    deduplicator.request('userInfo', () => mockAPI('用户信息', 1000)),
    deduplicator.request('userInfo', () => mockAPI('用户信息', 1000))
  ]
  
  const results = await Promise.all(requests)
  console.log('📋 去重结果:', results)
}

// ============== 7. 竞态条件处理 ==============
console.log('\n--- 🏃 7. 竞态条件处理 ---')

class SearchController {
  constructor() {
    this.currentSearchId = 0
  }
  
  async search(keyword) {
    // 生成唯一搜索ID
    const searchId = ++this.currentSearchId
    console.log(`🔍 开始搜索: "${keyword}" (ID: ${searchId})`)
    
    try {
      const result = await mockAPI(`搜索"${keyword}"结果`, Math.random() * 2000 + 500)
      
      // 检查是否是最新的搜索
      if (searchId === this.currentSearchId) {
        console.log(`✅ 搜索完成: ${result} (ID: ${searchId})`)
        return result
      } else {
        console.log(`🚫 丢弃过期搜索: ${result} (ID: ${searchId})`)
        return null
      }
    } catch (error) {
      console.log(`❌ 搜索失败: ${keyword} (ID: ${searchId})`)
      throw error
    }
  }
}

// 测试竞态条件
async function testRaceCondition() {
  console.log('🏃 竞态条件测试:')
  
  const searchController = new SearchController()
  
  // 快速连续搜索
  searchController.search('react')
  searchController.search('vue')
  searchController.search('angular')
  
  // 等待最后一个搜索
  setTimeout(async () => {
    const finalResult = await searchController.search('javascript')
    console.log('🎯 最终搜索结果:', finalResult)
  }, 100)
}

// ============== 8. 批量处理 ==============
console.log('\n--- 📦 8. 批量处理 ---')

class BatchProcessor {
  constructor(batchSize = 5, delay = 100) {
    this.batchSize = batchSize
    this.delay = delay
    this.queue = []
    this.processing = false
  }
  
  async add(item) {
    return new Promise((resolve, reject) => {
      this.queue.push({ item, resolve, reject })
      this.process()
    })
  }
  
  async process() {
    if (this.processing || this.queue.length === 0) {
      return
    }
    
    this.processing = true
    
    while (this.queue.length > 0) {
      const batch = this.queue.splice(0, this.batchSize)
      console.log(`📦 处理批次: ${batch.length} 个项目`)
      
      try {
        // 并发处理批次内的所有项目
        const results = await Promise.all(
          batch.map(({ item }) => this.processItem(item))
        )
        
        // 返回结果给调用者
        batch.forEach(({ resolve }, index) => {
          resolve(results[index])
        })
        
      } catch (error) {
        // 批次失败，拒绝所有
        batch.forEach(({ reject }) => {
          reject(error)
        })
      }
      
      // 批次间延迟
      if (this.queue.length > 0) {
        await new Promise(resolve => setTimeout(resolve, this.delay))
      }
    }
    
    this.processing = false
  }
  
  async processItem(item) {
    // 模拟处理单个项目
    await new Promise(resolve => setTimeout(resolve, Math.random() * 500))
    return `处理完成: ${item}`
  }
}

// 测试批量处理
async function testBatchProcessing() {
  console.log('📦 批量处理测试:')
  
  const processor = new BatchProcessor(3, 200)
  const items = ['项目1', '项目2', '项目3', '项目4', '项目5', '项目6', '项目7']
  
  const promises = items.map(item => processor.add(item))
  const results = await Promise.all(promises)
  
  console.log('📋 批量处理结果:', results)
}

// ============== 9. 实际应用示例 ==============
console.log('\n--- 💼 9. 实际应用示例 ---')

// 图片预加载
async function preloadImages(urls, concurrency = 3) {
  console.log(`🖼️ 预加载 ${urls.length} 张图片（并发数: ${concurrency}）`)
  
  const controller = new ConcurrencyController(concurrency)
  
  const loadImage = (url) => {
    return new Promise((resolve, reject) => {
      // 模拟图片加载
      setTimeout(() => {
        if (Math.random() > 0.1) { // 90%成功率
          resolve(`✅ ${url} 加载成功`)
        } else {
          reject(new Error(`❌ ${url} 加载失败`))
        }
      }, Math.random() * 1000 + 200)
    })
  }
  
  const tasks = urls.map(url => 
    controller.run(() => loadImage(url))
  )
  
  const results = await Promise.allSettled(tasks)
  
  const successful = results.filter(r => r.status === 'fulfilled').length
  const failed = results.length - successful
  
  console.log(`📊 预加载完成: 成功 ${successful}，失败 ${failed}`)
  return results
}

// 数据聚合
async function aggregateData() {
  console.log('📊 数据聚合示例:')
  
  const [userStats, orderStats, productStats] = await Promise.allSettled([
    mockAPI('用户统计', 800),
    mockAPI('订单统计', 1200),
    mockAPI('商品统计', 600)
  ])
  
  const dashboard = {
    users: userStats.status === 'fulfilled' ? userStats.value : '获取失败',
    orders: orderStats.status === 'fulfilled' ? orderStats.value : '获取失败',
    products: productStats.status === 'fulfilled' ? productStats.value : '获取失败',
    timestamp: new Date().toISOString()
  }
  
  console.log('📋 仪表板数据:', dashboard)
  return dashboard
}

// ============== 执行所有示例 ==============
async function runAllExamples() {
  console.log('\n🚀 开始执行所有并发示例...\n')
  
  // 基础并发
  await demonstratePromiseAll()
  await new Promise(resolve => setTimeout(resolve, 2000))
  
  await compareSerialVsParallel()
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  await demonstratePromiseAllSettled()
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  await demonstratePromiseRace()
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  // 高级控制
  await testConcurrencyControl()
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  await testRequestDeduplication()
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  await testRaceCondition()
  await new Promise(resolve => setTimeout(resolve, 3000))
  
  await testBatchProcessing()
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  // 实际应用
  await preloadImages(['img1.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg', 'img5.jpg'])
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  await aggregateData()
  
  console.log('\n=== 📚 并发处理总结 ===')
  console.log('1. 🚀 Promise.all - 全部成功才成功，提升性能')
  console.log('2. 🛡️ Promise.allSettled - 容错处理，等待全部完成')
  console.log('3. 🏁 Promise.race - 竞速执行，超时控制')
  console.log('4. 🎛️ 并发控制 - 限制同时执行数量，防止资源耗尽')
  console.log('5. 🔄 请求去重 - 防止重复请求，节省资源')
  console.log('6. 🏃 竞态处理 - 确保只处理最新结果')
  console.log('7. 📦 批量处理 - 分批处理大量数据')
  console.log('8. 💼 实际应用 - 图片预加载、数据聚合等')
  
  console.log('\n🎯 关键原则:')
  console.log('✅ 能并发就并发，提升性能')
  console.log('✅ 做好错误处理，增强健壮性')  
  console.log('✅ 控制并发数，避免资源耗尽')
  console.log('✅ 处理竞态条件，确保数据正确性')
  
  console.log('\n🎉 JavaScript 并发处理教程完成！')
}

// 启动示例
runAllExamples().catch(console.error) 